package cn.jdemo.type;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * @see java.lang.reflect.ParameterizedType 参数化类型（带有泛型的参数）：(1)带有泛型的成员变量(2)带有泛型的方法参数
 *
 * @see ParameterizedType#getTypeName() 全类型名称；例如:java.util.List<E>
 * @see ParameterizedType#getActualTypeArguments() 参数化类型<>中的实际参数类型(最外层的<>中的类型)；例如：List<List<Integer>> list_list成员变量，返回的是java.util.List<java.lang.Integer>
 * @see ParameterizedType#getRawType() 类型；例如:List<E> list，返回的是interface java.util.List
 * @see ParameterizedType#getOwnerType() 返回类型所在的类的Type；例如:(Map.Entry<String, Integer> param)方法参数，返回的是interface java.util.Map
 *
 * 字段变量
 * @see Field#getGenericType() 返回Type
 * @see Field#getType() 返回Class<?>
 *
 * 方法参数
 * @see Method#getGenericParameterTypes() 返回Type[]，若是参数化类型(泛型),可以获取参数更多信息
 * @see Method#getParameterTypes() 返回Class<?>[]
 *
 * 区别点:
 *   getGenericType()和getGenericParameterTypes(),可基于type获取参数类型相关更为完整的信息
 *   getType()和getParameterTypes(),只能获取class类型相关
 *
 * @date 2020/12/25
 */
public class Demo01_ParameterizedType<E> {

    /**
     * ParameterizedType
     */
    public List<E> list = null;
    public Class<?> cls = null;
    public Map<String,E> map = null;
    public List<List<Integer>> list_list = null;

    /**
     * 非ParameterizedType
     */
    public String str = null;

    public static void main(String[] args) {
        // test01();
        test02();
        // test03();
        // test04();
    }

    /**
     * 输出内容：
     * ********cn.jdemo.type.Demo01#list********
     * TypeName():java.util.List<E>
     * RawType():interface java.util.List
     * OwnerType():null
     * ActualTypeArguments():E
     *
     * ********cn.jdemo.type.Demo01#cls********
     * TypeName():java.lang.Class<?>
     * RawType():class java.lang.Class
     * OwnerType():null
     * ActualTypeArguments():?
     *
     * ********cn.jdemo.type.Demo01#map********
     * TypeName():java.util.Map<java.lang.String, E>
     * RawType():interface java.util.Map
     * OwnerType():null
     * ActualTypeArguments():java.lang.String
     * ActualTypeArguments():E
     *
     * ********cn.jdemo.type.Demo01#list_list********
     * TypeName():java.util.List<java.util.List<java.lang.Integer>>
     * RawType():interface java.util.List
     * OwnerType():null
     * ActualTypeArguments():java.util.List<java.lang.Integer>
     *
     * @see Field#getGenericType() 返回Type
     */
    public static void test01() {
        Field[] fields = Demo01_ParameterizedType.class.getFields();
        for (Field field:fields){
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                System.out.println("********"+ Demo01_ParameterizedType.class.getName()+"#"+field.getName()  +"********");
                System.out.println("TypeName():"+parameterizedType.getTypeName());
                System.out.println("RawType():"+parameterizedType.getRawType());
                System.out.println("OwnerType():"+parameterizedType.getOwnerType());
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type type :actualTypeArguments){
                    System.out.println("ActualTypeArguments():"+type.getTypeName());
                }
            }
        }
    }

    /**
     * 输出内容:
     * ********cn.jdemo.type.Demo01#list********
     * Name():java.util.List
     * TypeName():java.util.List
     * ********cn.jdemo.type.Demo01#cls********
     * Name():java.lang.Class
     * TypeName():java.lang.Class
     * ********cn.jdemo.type.Demo01#map********
     * Name():java.util.Map
     * TypeName():java.util.Map
     * ********cn.jdemo.type.Demo01#list_list********
     * Name():java.util.List
     * TypeName():java.util.List
     * ********cn.jdemo.type.Demo01#str********
     * Name():java.lang.String
     * TypeName():java.lang.String
     *
     * @see Field#getType() 返回Class<?>
     */
    public static void test02() {
        Field[] fields = Demo01_ParameterizedType.class.getFields();
        for (Field field:fields){
            Class<?> type = field.getType();
            System.out.println("********"+ Demo01_ParameterizedType.class.getName()+"#"+field.getName()  +"********");
            System.out.println("Name():"+ type.getName());
            System.out.println("TypeName():"+ type.getTypeName());
        }
    }

    /**
     * 输出内容
     * ******cn.jdemo.type.Amethod01********
     * TypeName():java.util.Map.java.util.Map$Entry<java.lang.String, java.lang.Integer>
     * RawType():interface java.util.Map$Entry
     * OwnerType():interface java.util.Map
     * ActualTypeArguments():java.lang.String
     * ActualTypeArguments():java.lang.Integer
     *
     * @see Method#getGenericParameterTypes() 返回Type[]
     */
    public static void test03() {
        try {
            Method method01 = A.class.getMethod("method01", Map.Entry.class);
            Type[] genericParameterTypes = method01.getGenericParameterTypes();
            for (Type genericParameterType: genericParameterTypes){
                if (genericParameterType instanceof ParameterizedType){
                    ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
                    System.out.println("******"+A.class.getName()+method01.getName()+"********");
                    System.out.println("TypeName():"+parameterizedType.getTypeName());
                    System.out.println("RawType():"+parameterizedType.getRawType());
                    System.out.println("OwnerType():"+parameterizedType.getOwnerType());
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    for (Type type :actualTypeArguments){
                        System.out.println("ActualTypeArguments():"+type.getTypeName());
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**输出内容:
     * ******cn.jdemo.type.Amethod01********
     * TypeName():java.util.Map$Entry
     *
     * @see Method#getParameterTypes() 返回Class<?>[]
     */
    public static void test04() {
        try {
            Method method01 = A.class.getMethod("method01", Map.Entry.class);
            Class<?>[] parameterTypes = method01.getParameterTypes();
            for (Class parameterType: parameterTypes){
                System.out.println("******"+A.class.getName()+method01.getName()+"********");
                System.out.println("TypeName():"+parameterType.getTypeName());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
class A{
    public void method01(Map.Entry<String,Integer> param){
        System.out.println(param.getKey()+":"+param.getValue());
    }
}
